/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wdullaer.datetimepickerexampleohos;

import com.wdullaer.EventHelper;
import com.wdullaer.materialdatetimepicker.common.Log;
import com.wdullaer.materialdatetimepicker.date.*;
import junit.framework.TestCase;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.delegation.AbilityDelegatorRegistry;
import ohos.aafwk.ability.delegation.IAbilityDelegator;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.media.image.common.Position;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.util.Calendar;

public class DatePickerTest extends TestCase {

    private static IAbilityDelegator sAbilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
    private Ability ability;
    private Button dateButton;
    private Checkbox showVersion2;
    private Checkbox modeDarkDate;
    private Checkbox modeCustomAccentDate;
    private Checkbox vibrateDate;
    private Checkbox switchOrientation;
    private Checkbox dismissDate;
    private Checkbox showYearFirst;
    private Checkbox titleDate;
    private Checkbox limitSelectableDays;
    private Checkbox highlightDays;
    private Checkbox defaultSelection;
    private DatePickerDialog dpd;

    private Text mDatePickerHeaderView;
    private DirectionalLayout mMonthAndDayView;
    private Text mSelectedMonthTextView;
    private Text mSelectedDayTextView;
    private Text mYearView;
    private AccessibleDateAnimator mAnimator;
    private DayPickerGroup mDayPickerGroup;
    private Button prevButton;
    private Button nextButton;
    private DayPickerView dayPickerView;
    private YearPickerView mYearPickerView;
    Button okButton;
    Button cancelButton;

    @Before
    public void setUp() throws Exception {
        ability = EventHelper.startAbility(MainAbility.class);
        EventHelper.waitForActive(ability, 5);
        Thread.sleep(2000);
        TabList tabList = (TabList) ability.findComponentById(ResourceTable.Id_tab_list);
        sAbilityDelegator.runOnUIThreadSync(() -> tabList.selectTabAt(1));
        Thread.sleep(500);
        dateButton = (Button) ability.findComponentById(ResourceTable.Id_date_button);
        showVersion2 = (Checkbox) ability.findComponentById(ResourceTable.Id_show_version_2);
        modeDarkDate = (Checkbox) ability.findComponentById(ResourceTable.Id_mode_dark_date);
        modeCustomAccentDate = (Checkbox) ability.findComponentById(ResourceTable.Id_mode_custom_accent_date);
        vibrateDate = (Checkbox) ability.findComponentById(ResourceTable.Id_vibrate_date);
        switchOrientation = (Checkbox) ability.findComponentById(ResourceTable.Id_switch_orientation);
        dismissDate = (Checkbox) ability.findComponentById(ResourceTable.Id_dismiss_date);
        showYearFirst = (Checkbox) ability.findComponentById(ResourceTable.Id_show_year_first);
        titleDate = (Checkbox) ability.findComponentById(ResourceTable.Id_title_date);
        limitSelectableDays = (Checkbox) ability.findComponentById(ResourceTable.Id_limit_dates);
        highlightDays = (Checkbox) ability.findComponentById(ResourceTable.Id_highlight_dates);
        defaultSelection = (Checkbox) ability.findComponentById(ResourceTable.Id_default_selection);
    }

    @After
    public void tearDown() throws Exception {
        Thread.sleep(500);
        sAbilityDelegator.stopAbility(ability);
        EventHelper.clearAbilities();
    }

    private void showDialog() {
        Calendar now = Calendar.getInstance();
        if (defaultSelection.isChecked()) {
            now.add(Calendar.DATE, 7);
        }
        if (dpd == null) {
            dpd = DatePickerDialog.newInstance(
                ability.getContext(),
                null,
                now.get(Calendar.YEAR),
                now.get(Calendar.MONTH),
                now.get(Calendar.DAY_OF_MONTH)
            );
        } else {
            dpd.initialize(
                null,
                now.get(Calendar.YEAR),
                now.get(Calendar.MONTH),
                now.get(Calendar.DAY_OF_MONTH)
            );
        }
        dpd.setAlignment(LayoutAlignment.CENTER);
        dpd.setThemeDark(modeDarkDate.isChecked());
        dpd.vibrate(vibrateDate.isChecked());
        dpd.dismissOnPause(dismissDate.isChecked());
        dpd.showYearPickerFirst(showYearFirst.isChecked());
        dpd.setVersion(showVersion2.isChecked() ? DatePickerDialog.Version.VERSION_2 : DatePickerDialog.Version.VERSION_1);
        if (modeCustomAccentDate.isChecked()) {
            dpd.setAccentColor(Color.getIntColor("#9C27B0"));
        }
        if (titleDate.isChecked()) {
            dpd.setTitle("DatePicker Title");
        }
        if (highlightDays.isChecked()) {
            Calendar date1 = Calendar.getInstance();
            Calendar date2 = Calendar.getInstance();
            date2.add(Calendar.WEEK_OF_MONTH, -1);
            Calendar date3 = Calendar.getInstance();
            date3.add(Calendar.WEEK_OF_MONTH, 1);
            Calendar[] days = {date1, date2, date3};
            dpd.setHighlightedDays(days);
        }
        if (limitSelectableDays.isChecked()) {
            Calendar[] days = new Calendar[13];
            for (int i = -6; i < 7; i++) {
                Calendar day = Calendar.getInstance();
                day.add(Calendar.DAY_OF_MONTH, i * 2);
                days[i + 6] = day;
            }
            dpd.setSelectableDays(days);
        }
        if (switchOrientation.isChecked()) {
            if (dpd.getVersion() == DatePickerDialog.Version.VERSION_1) {
                dpd.setScrollOrientation(DatePickerDialog.ScrollOrientation.HORIZONTAL);
            } else {
                dpd.setScrollOrientation(DatePickerDialog.ScrollOrientation.VERTICAL);
            }
        }
        dpd.setOnCancelListener(dialog -> {
            dpd = null;
        });
        dpd.show();
    }

    private Component loadDialogComponents() {
        Component root = ((ComponentContainer) dpd.getContentCustomComponent()).getComponentAt(0);
        mDatePickerHeaderView = (Text) root.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_date_picker_header);
        mMonthAndDayView = (DirectionalLayout) root.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_date_picker_month_and_day);
        mSelectedMonthTextView = (Text) root.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_date_picker_month);
        mSelectedDayTextView = (Text) root.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_date_picker_day);
        mYearView = (Text) root.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_date_picker_year);
        mAnimator = (AccessibleDateAnimator) root.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_animator);
        mDayPickerGroup = (DayPickerGroup) mAnimator.getComponentAt(0);
        prevButton = (Button) mDayPickerGroup.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_previous_month_arrow);
        nextButton = (Button) mDayPickerGroup.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_next_month_arrow);
        dayPickerView = (DayPickerView) mDayPickerGroup.getComponentAt(0);
        mYearPickerView = (YearPickerView) mAnimator.getComponentAt(1);
        Log.i("zh", "mYearPickerView:" + mYearPickerView);
        okButton = (Button) root.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_ok);
        cancelButton = (Button) root.findComponentById(com.wdullaer.materialdatetimepicker.ResourceTable.Id_mdtp_cancel);
        return root;
    }

    @Test
    public void testShowVersion2() throws InterruptedException {
        assertNotNull(dateButton);
        assertNotNull(showVersion2);
        sAbilityDelegator.runOnUIThreadSync(() -> showVersion2.simulateClick());
        Thread.sleep(500);
        sAbilityDelegator.runOnUIThreadSync(() -> dateButton.simulateClick());
        Thread.sleep(500);

        sAbilityDelegator.runOnUIThreadSync(this::showDialog);
        Thread.sleep(1000);

        assertTrue(dpd.isShowing());
        assertEquals(DatePickerDialog.Version.VERSION_2, dpd.getVersion());

        loadDialogComponents();
        assertEquals(Component.HIDE, mDatePickerHeaderView.getVisibility());
        assertEquals(Component.VISIBLE, prevButton.getVisibility());
        assertEquals(Component.VISIBLE, nextButton.getVisibility());
    }

    @Test
    public void testDarkMode() throws InterruptedException {
        assertNotNull(dateButton);
        assertNotNull(modeDarkDate);
        sAbilityDelegator.runOnUIThreadSync(() -> modeDarkDate.simulateClick());
        Thread.sleep(500);
        sAbilityDelegator.runOnUIThreadSync(() -> dateButton.simulateClick());
        Thread.sleep(500);

        sAbilityDelegator.runOnUIThreadSync(this::showDialog);
        Thread.sleep(1000);

        assertTrue(dpd.isShowing());

        int srcColor = ability.getColor(com.wdullaer.materialdatetimepicker.ResourceTable.Color_mdtp_date_picker_view_animator_dark_theme);
        Component root = loadDialogComponents();
        ShapeElement element = (ShapeElement) root.getBackgroundElement();
        RgbColor color = element.getRgbColors()[0];
        int dstColor = color.asArgbInt();

        assertEquals(srcColor, dstColor);
    }

    @Test
    public void testAccentColor() throws InterruptedException {
        assertNotNull(dateButton);
        assertNotNull(modeCustomAccentDate);
        sAbilityDelegator.runOnUIThreadSync(() -> modeCustomAccentDate.simulateClick());
        Thread.sleep(500);
        sAbilityDelegator.runOnUIThreadSync(() -> dateButton.simulateClick());
        Thread.sleep(500);

        sAbilityDelegator.runOnUIThreadSync(this::showDialog);
        Thread.sleep(1000);

        assertTrue(dpd.isShowing());

        int srcColor = Color.getIntColor("#9C27B0");
        loadDialogComponents();
        int dstColor = okButton.getTextColor().getValue();

        assertEquals(srcColor, dstColor);
    }

    @Test
    public void testSwitchOritation() throws InterruptedException {
        assertNotNull(dateButton);
        assertNotNull(switchOrientation);
        sAbilityDelegator.runOnUIThreadSync(() -> switchOrientation.simulateClick());
        Thread.sleep(500);
        sAbilityDelegator.runOnUIThreadSync(() -> dateButton.simulateClick());
        Thread.sleep(500);

        sAbilityDelegator.runOnUIThreadSync(this::showDialog);
        Thread.sleep(1000);

        assertTrue(dpd.isShowing());

        loadDialogComponents();
        assertEquals(DatePickerDialog.ScrollOrientation.HORIZONTAL, dpd.getScrollOrientation());
        assertEquals(Component.VISIBLE, prevButton.getVisibility());
        assertEquals(Component.VISIBLE, nextButton.getVisibility());
    }

    @Test
    public void testShowYearFirst() throws InterruptedException {
        assertNotNull(dateButton);
        assertNotNull(showYearFirst);
        sAbilityDelegator.runOnUIThreadSync(() -> showYearFirst.simulateClick());
        Thread.sleep(500);
        sAbilityDelegator.runOnUIThreadSync(() -> dateButton.simulateClick());
        Thread.sleep(500);

        sAbilityDelegator.runOnUIThreadSync(this::showDialog);
        Thread.sleep(1000);

        assertTrue(dpd.isShowing());

        loadDialogComponents();
        assertEquals(Component.HIDE, mDayPickerGroup.getVisibility());
        assertEquals(Component.VISIBLE, mYearPickerView.getVisibility());
    }

    @Test
    public void testHighlightDays() throws InterruptedException {
        assertNotNull(dateButton);
        assertNotNull(showYearFirst);
        sAbilityDelegator.runOnUIThreadSync(() -> highlightDays.simulateClick());
        Thread.sleep(500);
        sAbilityDelegator.runOnUIThreadSync(() -> dateButton.simulateClick());
        Thread.sleep(500);

        sAbilityDelegator.runOnUIThreadSync(this::showDialog);
        Thread.sleep(1000);

        assertTrue(dpd.isShowing());

        loadDialogComponents();

        Assert.assertFalse(dpd.isHighlighted(1990, 2, 1));
        Calendar date1 = Calendar.getInstance();
        Calendar date2 = Calendar.getInstance();
        date2.add(Calendar.WEEK_OF_MONTH, -1);
        Calendar date3 = Calendar.getInstance();
        date3.add(Calendar.WEEK_OF_MONTH, 1);

        assertTrue(dpd.isHighlighted(date1.get(Calendar.YEAR), date1.get(Calendar.MONTH), date1.get(Calendar.DAY_OF_MONTH)));
        assertTrue(dpd.isHighlighted(date2.get(Calendar.YEAR), date2.get(Calendar.MONTH), date2.get(Calendar.DAY_OF_MONTH)));
        assertTrue(dpd.isHighlighted(date3.get(Calendar.YEAR), date3.get(Calendar.MONTH), date3.get(Calendar.DAY_OF_MONTH)));
    }

    private Position getPositionOfDay(SimpleMonthView monthView, int target) {
        Position pos = new Position();
        int step = monthView.getCellWidth() / 3;
        for (int i = step; i < monthView.getWidth(); i += step) {
            for (int j = step; j < monthView.getHeight(); j += step) {
                int day = monthView.getDayFromLocation(i, j);
                Log.i("MonthFragment", "zzz [" + i + ", " + j + "] day:" + day + ", target:" + target + ", monthView.rect:" + monthView.getComponentPosition());
                if (day == target) {
                    pos.posX = i;
                    pos.posY = j;
                    break;
                }
            }
        }
        return pos;
    }
}